package com.mv.CodeStorage;

import java.io.OutputStream;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.mv.service.security.UserDetailsImpl;

import beans.ApplicationBean;
import beans.ApplicationBeanValidator;
import Export.CodeStorageContext.CodeStorageFactory;
import Interfaces.IDBItem;
import Interfaces.TagType;
import Models.Aplikace;
import Models.User;

@Controller
public class ApplicationController {
	
	@InitBinder
	protected void initBinder(WebDataBinder binder) {
	    binder.setValidator(new ApplicationBeanValidator());
	}
	
	@RequestMapping(value = "/application/{appId}/display", method = RequestMethod.GET)
	public String display(Model model, @PathVariable("appId") int id){
		
		Aplikace appDb = CodeStorageFactory.LoadAplikaceSimpleLight(id);
		
		if (appDb == null){
			throw new ResourceNotFoundException("Aplikace s daným ID neexistuje!"); // 404 
		}
		
		// loads tags for application object
		appDb = CodeStorageFactory.FetchAplikaceTag(appDb);
		
		ApplicationBean app = new ApplicationBean();
		app.setNazev(appDb.getNazev());
		app.setPopis(appDb.getPopis());
		app.setPocetStazeni(appDb.getPocetStazeni());
		app.setTags(concatTagNames(appDb.getTags()));
		app.setHod(appDb.getPrumerHodnoceni());
		
		model.addAttribute("title", "Code Storage - " +app.getNazev());
		model.addAttribute("page", 2);
		model.addAttribute("appId", id);
		model.addAttribute("app", app);
		
		return "application/display";
	}
	
	@RequestMapping(value = "/application/{appId}/delete", method = RequestMethod.GET)
	public String delete(HttpServletRequest request, Model model, @PathVariable("appId") int id){
		
		User usr = CodeStorageFactory.LoadUserSimple(request.getUserPrincipal().getName());
		CodeStorageFactory.FetchUserAplikace(usr);
		
		Aplikace appDb = null;
		for(IDBItem item: usr.getChilds()){
			appDb = (Aplikace)item;
			if(appDb.getID() != id)
				appDb = null;
			else
				break;
		}
		
		
		if (appDb == null){
			throw new ResourceNotFoundException("Aplikace s daným ID neexistuje!"); // 404 
		}
		
		appDb = CodeStorageFactory.FetchAplikaceTag(appDb);
		
		CodeStorageFactory.DeleteITem(appDb);
		
		return "redirect:/profile";
	}
	
	@RequestMapping(value = "/application/{appId}/rate/{rating}", method = RequestMethod.GET)
	public String rate(HttpServletRequest request, Model model, @PathVariable("appId") int id, @PathVariable("rating") int rating){
		if (rating >= 1 & rating <=5)
		{
			String ip = request.getRemoteAddr();
			CodeStorageFactory.AddAplikaceHodnoceni(id, ip, rating);
		}
		return String.format("redirect:/application/%d/display", id);
	}
	
	private String concatTagNames(List<Models.Tag> tags)
	{
		StringBuilder sb = new StringBuilder();
		for(Models.Tag tg : tags){
			sb.append(tg.GetHodnota());
			sb.append("; ");
		}
		
		return sb.toString();
	}
	
	@RequestMapping(value = "/application/{appId}/icon", method = RequestMethod.GET)
	public void icon(HttpServletRequest request, HttpServletResponse response, @PathVariable("appId") int id) throws Exception {
		
		byte[] iconBytes = CodeStorageFactory.LoadAplikaceIkon(id);
		
		if (iconBytes == null){
			throw new ResourceNotFoundException("Aplikace s daným ID neexistuje!"); // 404 
		}
		
		String mimeType = "image/jpeg";
		String fileName = "icon"+id+".jpg";
		
		// set content attributes for the response
        response.setContentType(mimeType);
        response.setContentLength((int) iconBytes.length);
 
        // set headers for the response
        String headerKey = "Content-Disposition";
        String headerValue = String.format("attachment; filename=\"%s\"", fileName);
        response.setHeader(headerKey, headerValue);
 
        // get output stream of the response
        OutputStream outStream = response.getOutputStream();
 
        outStream.write(iconBytes, 0, iconBytes.length);
        
        outStream.close(); 
	}
	
	@RequestMapping(value = "/application/{appId}/content", method = RequestMethod.GET)
	public void content(HttpServletRequest request, HttpServletResponse response, @PathVariable("appId") int id) throws Exception {
		
		Aplikace app = CodeStorageFactory.LoadAplikaceSimpleLight(id);
		byte[] contentBytes = CodeStorageFactory.LoadAplikaceObsah(id);
		
		if (contentBytes == null){
			throw new ResourceNotFoundException("Aplikace s daným ID neexistuje!"); // 404 
		}
		
		String mimeType = "application/x-zip-compressed";
		String fileName = app.GetFileName();
		
		// set content attributes for the response
        response.setContentType(mimeType);
        response.setContentLength((int) contentBytes.length);
 
        // set headers for the response
        String headerKey = "Content-Disposition";
        String headerValue = String.format("attachment; filename=\"%s\"", fileName);
        response.setHeader(headerKey, headerValue);
 
        // get output stream of the response
        OutputStream outStream = response.getOutputStream();
 
        outStream.write(contentBytes, 0, contentBytes.length);
        
        outStream.close();
        
        CodeStorageFactory.addAplikaceStazeni(id);
	}
	
	@RequestMapping(value = "/application/upload", method = RequestMethod.GET)
	public String upload(Model model){

		model.addAttribute("title", "Code Storage - Přidání aplikace");
		model.addAttribute("page", 4);
		model.addAttribute("application", new ApplicationBean());
		
		return "application/upload";
	}
	
	@RequestMapping(value = "/application/doUpload", method = RequestMethod.POST)
	public String doUpload(@Validated @ModelAttribute("application") ApplicationBean app, BindingResult result, Model model) throws Exception
	{
		// logged in user
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		UserDetailsImpl user = (UserDetailsImpl)authentication.getPrincipal();
		
		if (result.hasErrors()){
			
			if (app.isEditing())
			{
				model.addAttribute("title", "Code Storage - Editace aplikace");
				model.addAttribute("page", 5);				
			}else{
				model.addAttribute("title", "Code Storage - Přidání aplikace");
				model.addAttribute("page", 4);	
			}
			
			return "/application/upload";
		}
		
		int appId;
		if (!app.isEditing())
		{
			byte[] bytes = app.getContent().getBytes();
			
			Models.Aplikace appDb = new Models.Aplikace(user.getId(), app.getNazev(), app.getPopis(), app.getContent().getOriginalFilename(), bytes, app.getIcon().getBytes());
			Export.CodeStorageContext.CodeStorageFactory.SaveItem(appDb);
			
			String[] tags = app.getTags().split(";");
			for(String tag : tags){
				tag = tag.trim().toLowerCase();
				if (isBlank(tag))
					continue;
				
				Models.Tag tagDb = new Models.Tag(appDb, TagType.Others, tag);
				Export.CodeStorageContext.CodeStorageFactory.SaveItem(tagDb);
			}
			appId = appDb.getID();
		}else{			
			Models.Aplikace appDb = Export.CodeStorageContext.CodeStorageFactory.LoadAplikaceSimple(app.getId());
			
			if (appDb.getMasterObjectID() != user.getId()){
				throw new ResourceNotFoundException("");
			}
			
			appDb.setNazev(app.getNazev());
			appDb.setPopis(app.getPopis());
			appDb.setModified(true); // hardcoded because of tags
			
			if (app.getIcon().getSize() != 0){
				appDb.setIkona(app.getIcon().getBytes());
			}
			if (app.getContent().getSize() != 0){
				appDb.setObsah(app.getContent().getBytes());
			}		
			Export.CodeStorageContext.CodeStorageFactory.SaveItem(appDb);
			
			// removes old tags
			Export.CodeStorageContext.CodeStorageFactory.FetchAplikaceTag(appDb);
			for(Models.Tag tg : appDb.getTags()){
				Export.CodeStorageContext.CodeStorageFactory.DeleteITem(tg);
			}

			// saves new tags
			String[] tags = app.getTags().split(";");
			for(String tag : tags){
				tag = tag.trim().toLowerCase();
				if (isBlank(tag))
					continue;
				
				Models.Tag tagDb = new Models.Tag(appDb, TagType.Others, tag);
				Export.CodeStorageContext.CodeStorageFactory.SaveItem(tagDb);
			}
			
			appId = appDb.getID();
		}
		
		return String.format("redirect:/application/%d/display", appId);
	}
	
	@RequestMapping(value = "/application/{appId}/edit", method = RequestMethod.GET)
	public String edit(Model model, @PathVariable("appId") int id){
		
		// logged in user
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		UserDetailsImpl user = (UserDetailsImpl)authentication.getPrincipal();
		
		Aplikace appDb = CodeStorageFactory.LoadAplikaceSimpleLight(id);

		if (appDb.getMasterObjectID() != user.getId()){
			throw new ResourceNotFoundException("");
		}
		
		if (appDb == null){
			throw new ResourceNotFoundException("Aplikace s daným ID neexistuje!"); // 404 
		}
		
		// loads tags for application object
		appDb = CodeStorageFactory.FetchAplikaceTag(appDb);
		
		ApplicationBean app = new ApplicationBean();
		app.setId(appDb.getID());
		app.setNazev(appDb.getNazev());
		app.setPopis(appDb.getPopis());
		app.setPocetStazeni(appDb.getPocetStazeni());
		app.setTags(concatTagNames(appDb.getTags()));
		app.setHod(appDb.getPrumerHodnoceni());
		app.setEditing(true);
		
		model.addAttribute("title", "Code Storage - Editace aplikace");
		model.addAttribute("page", 5);
		
		model.addAttribute("application", app);
		
		return "application/upload";
	}
	
	private static boolean isBlank(String str) {
	      int strLen;
	      if (str == null || (strLen = str.length()) == 0) {
	          return true;
	      }
	      for (int i = 0; i < strLen; i++) {
	          if ((Character.isWhitespace(str.charAt(i)) == false)) {
	              return false;
	          }
	      }
	      return true;
	  }
}
